using System;
using System.Runtime.InteropServices;
using System.Text;

namespace WeighClient.Utils
{
    /// <summary>
    /// 身份证读卡器工具类 - 调用 dlls/Sjdll 路径下的DLL
    /// </summary>
    public class IDCardReaderUtil_Sjdll
    {
        private static bool _isConnected = false;
        private static readonly byte[] _dataBuffer = new byte[1024];

        /// <summary>
        /// 是否已连接
        /// </summary>
        public static bool IsConnected => _isConnected;

        /// <summary>
        /// 初始化设备（调用 dlls/Sjdll 路径下的DLL）
        /// </summary>
        /// <param name="comPort"> COM端口号，例如：1001表示USB端口，5表示COM5 </param>
        /// <returns> 是否成功 </returns>
        public static bool InitDevice(int comPort = 1001)
        {
            try
            {
                int result = InitComm(comPort);

                if (result > 0)
                {
                    _isConnected = true;
                    Console.WriteLine($"设备初始化成功（Sjdll），端口: {comPort}");
                    return true;
                }
                else
                {
                    Console.WriteLine($"设备初始化失败（Sjdll），错误代码: {result}");
                    return false;
                }
            }
            catch (DllNotFoundException ex)
            {
                Console.WriteLine($"DLL文件未找到（Sjdll）: {ex.Message}");
                Console.WriteLine("请确保以下DLL文件在 dlls/Sjdll 目录:");
                Console.WriteLine("- termb.dll");
                Console.WriteLine("- Sdtapi.dll");
                Console.WriteLine("- libwlt2bmp.dll");
                Console.WriteLine("- USBHIDHelper.dll");
                Console.WriteLine("- DLL_File.dll");
                Console.WriteLine("- msvcr100.dll");
                return false;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"设备初始化异常（Sjdll）: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 读取身份证信息（调用 dlls/Sjdll 路径下的DLL）
        /// </summary>
        /// <returns> 身份证信息对象 </returns>
        public static IDCardInfo ReadCard()
        {
            var cardInfo = new IDCardInfo();

            try
            {
                if (!_isConnected)
                {
                    cardInfo.ErrorMessage = "设备未连接，请先调用InitDevice()";
                    Console.WriteLine(cardInfo.ErrorMessage);
                    return cardInfo;
                }

                // 1. 卡认证
                int authResult = Authenticate();
                if (authResult <= 0)
                {
                    cardInfo.ErrorMessage = $"卡认证失败（Sjdll），错误代码: {authResult}";
                    Console.WriteLine(cardInfo.ErrorMessage);
                    return cardInfo;
                }

                // 2. 读卡操作
                int readResult = Read_Content(1);
                if (readResult <= 0)
                {
                    cardInfo.ErrorMessage = $"读卡失败（Sjdll），错误代码: {readResult}";
                    Console.WriteLine(cardInfo.ErrorMessage);
                    return cardInfo;
                }

                // 3. 读取各项信息
                ReadBasicInfo(cardInfo);

                // 4. 读取照片 ReadPhoto(cardInfo);

                cardInfo.IsSuccess = true;
                cardInfo.ReadTime = DateTime.Now;

                Console.WriteLine("读卡成功（Sjdll）！");
            }
            catch (Exception ex)
            {
                cardInfo.ErrorMessage = $"读卡异常（Sjdll）: {ex.Message}";
                Console.WriteLine(cardInfo.ErrorMessage);
            }

            return cardInfo;
        }

        /// <summary>
        /// 关闭设备（调用 dlls/Sjdll 路径下的DLL）
        /// </summary>
        /// <returns> 是否成功 </returns>
        public static bool CloseDevice()
        {
            try
            {
                int result = CloseComm();

                _isConnected = false;

                if (result > 0)
                {
                    Console.WriteLine("设备已关闭（Sjdll）");
                    return true;
                }
                else
                {
                    Console.WriteLine($"设备关闭失败（Sjdll），错误代码: {result}");
                    return false;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"设备关闭异常（Sjdll）: {ex.Message}");
                return false;
            }
        }

        #region 私有方法

        private static void ReadBasicInfo(IDCardInfo cardInfo)
        {
            try
            {
                // 读取姓名
                getName(_dataBuffer, _dataBuffer.Length);
                cardInfo.Name = BytesToString(_dataBuffer);
                // 读取身份证号
                getIDNum(_dataBuffer, _dataBuffer.Length);
                cardInfo.IDNumber = BytesToString(_dataBuffer);

                string SJIDCardPort = App.GetConfig().SJIDCardPort;
                int inport = Convert.ToInt32(SJIDCardPort);

                IC_GetIDSnr(inport, _dataBuffer, _dataBuffer.Length);
                cardInfo.MacCard = BytesToString(_dataBuffer);
            }
            catch (Exception ex)
            {
                cardInfo.ErrorMessage += $"读取基本信息失败（Sjdll）: {ex.Message}; ";
            }
        }

        private static void ReadPhoto(IDCardInfo cardInfo)
        {
            try
            {
                int photoSize = GetBmpPhotoExt();
                if (photoSize > 0)
                {
                    byte[] photoBuffer = new byte[photoSize];
                    getJPGPhotoBase64(photoBuffer, photoSize);
                    cardInfo.PhotoBase64 = BytesToBase64(photoBuffer);
                }
            }
            catch (Exception ex)
            {
                cardInfo.ErrorMessage += $"读取照片失败（Sjdll）: {ex.Message}; ";
            }
        }

        #endregion 私有方法

        #region DLL函数导入声明 - dlls/Sjdll 路径

        /// <summary> 初始化通信端口 </summary> <param name="iPort">端口号</param> <returns>返回值：>0成功，<=0失败</returns>
        [DllImport("dlls/Sjdll/termb.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern int InitComm(int iPort);

        /// <summary> 关闭通信端口 </summary> <returns>返回值：>0成功，<=0失败</returns>
        [DllImport("dlls/Sjdll/termb.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern int CloseComm();

        /// <summary> 卡认证 </summary> <returns>返回值：>0成功，<=0失败</returns>
        [DllImport("dlls/Sjdll/termb.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern int Authenticate();

        /// <summary> 读卡操作 </summary> <param name="active">激活标志</param> <returns>返回值：>0成功，<=0失败</returns>
        [DllImport("dlls/Sjdll/termb.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern int Read_Content(int active);

        /// <summary>
        /// 获取姓名
        /// </summary>
        /// <param name="data">   数据缓冲区 </param>
        /// <param name="cbData"> 数据长度 </param>
        [DllImport("dlls/Sjdll/termb.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void getName(byte[] data, int cbData);

        /// <summary>
        /// 获取性别
        /// </summary>
        /// <param name="data">   数据缓冲区 </param>
        /// <param name="cbData"> 数据长度 </param>
        [DllImport("dlls/Sjdll/termb.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void getSex(byte[] data, int cbData);

        /// <summary>
        /// 获取民族
        /// </summary>
        /// <param name="data">   数据缓冲区 </param>
        /// <param name="cbData"> 数据长度 </param>
        [DllImport("dlls/Sjdll/termb.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void getNation(byte[] data, int cbData);

        /// <summary>
        /// 获取出生日期
        /// </summary>
        /// <param name="data">   数据缓冲区 </param>
        /// <param name="cbData"> 数据长度 </param>
        [DllImport("dlls/Sjdll/termb.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void getBirth(byte[] data, int cbData);

        /// <summary>
        /// 获取地址
        /// </summary>
        /// <param name="data">   数据缓冲区 </param>
        /// <param name="cbData"> 数据长度 </param>
        [DllImport("dlls/Sjdll/termb.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void getAddress(byte[] data, int cbData);

        /// <summary>
        /// 获取身份证号
        /// </summary>
        /// <param name="data">   数据缓冲区 </param>
        /// <param name="cbData"> 数据长度 </param>
        [DllImport("dlls/Sjdll/termb.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void getIDNum(byte[] data, int cbData);

        /// <summary>
        /// 获取签发机关
        /// </summary>
        /// <param name="data">   数据缓冲区 </param>
        /// <param name="cbData"> 数据长度 </param>
        [DllImport("dlls/Sjdll/termb.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void getIssue(byte[] data, int cbData);

        /// <summary>
        /// 获取有效期
        /// </summary>
        /// <param name="data">   数据缓冲区 </param>
        /// <param name="cbData"> 数据长度 </param>
        [DllImport("dlls/Sjdll/termb.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void getPeriod(byte[] data, int cbData);

        /// <summary>
        /// 获取照片数据长度
        /// </summary>
        /// <returns> 照片数据长度 </returns>
        [DllImport("dlls/Sjdll/termb.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern int GetBmpPhotoExt();

        /// <summary>
        /// 获取照片Base64数据
        /// </summary>
        /// <param name="data">   数据缓冲区 </param>
        /// <param name="cbData"> 数据长度 </param>
        [DllImport("dlls/Sjdll/termb.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void getJPGPhotoBase64(byte[] data, int cbData);

        /// <summary>
        /// 获取指纹数据
        /// </summary>
        /// <param name="data">   数据缓冲区 </param>
        /// <param name="cbData"> 数据长度 </param>
        [DllImport("dlls/Sjdll/termb.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void getFingerPrint(byte[] data, int cbData);

        /// <summary>
        /// 获取SAM ID
        /// </summary>
        /// <param name="data">   数据缓冲区 </param>
        /// <param name="cbData"> 数据长度 </param>
        [DllImport("dlls/Sjdll/termb.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void getSAMID(byte[] data, int cbData);

        /// <summary>
        /// 获取身份证物理卡号
        /// </summary>
        /// <param name="iPort">  设备端口 </param>
        /// <param name="data">   数据缓冲区 </param>
        /// <param name="cbData"> 数据长度 </param>
        [DllImport("dlls/Sjdll/termb.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern void IC_GetIDSnr(int iPort, byte[] data, int cbdata);

        #endregion DLL函数导入声明 - dlls/Sjdll 路径

        #region 辅助方法

        /// <summary>
        /// 将字节数组转换为字符串（GB2312编码）
        /// </summary>
        public static string BytesToString(byte[] data)
        {
            if (data == null || data.Length == 0)
                return string.Empty;

            int length = Array.IndexOf(data, (byte)0);
            if (length == -1)
                length = data.Length;

            try
            {
                // 尝试使用GB2312编码
                return Encoding.GetEncoding("GB2312").GetString(data, 0, length);
            }
            catch
            {
                try
                {
                    // 如果GB2312不可用，尝试注册编码提供程序（.NET Core/.NET 5+）
#if NETCOREAPP || NET5_0_OR_GREATER
                    Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
                    return Encoding.GetEncoding("GB2312").GetString(data, 0, length);
#else
                    // .NET Framework 回退到默认编码
                    return Encoding.Default.GetString(data, 0, length);
#endif
                }
                catch
                {
                    // 最后的回退方案
                    return Encoding.Default.GetString(data, 0, length);
                }
            }
        }

        /// <summary>
        /// 将字节数组转换为Base64字符串
        /// </summary>
        public static string BytesToBase64(byte[] data)
        {
            if (data == null || data.Length == 0)
                return string.Empty;

            return Convert.ToBase64String(data);
        }

        #endregion 辅助方法
    }

    #region 身份证信息数据模型

    /// <summary>
    /// 身份证信息数据模型
    /// </summary>
    public class IDCardInfo
    {
        /// <summary>
        /// 姓名
        /// </summary>
        public string Name { get; set; } = string.Empty;

        /// <summary>
        /// 性别
        /// </summary>
        public string Gender { get; set; } = string.Empty;

        /// <summary>
        /// 民族
        /// </summary>
        public string Nation { get; set; } = string.Empty;

        /// <summary>
        /// 出生日期
        /// </summary>
        public string BirthDate { get; set; } = string.Empty;

        /// <summary>
        /// 地址
        /// </summary>
        public string Address { get; set; } = string.Empty;

        /// <summary>
        /// 身份证号
        /// </summary>
        public string IDNumber { get; set; } = string.Empty;

        /// <summary>
        /// 签发机关
        /// </summary>
        public string IssueAuthority { get; set; } = string.Empty;

        /// <summary>
        /// 有效期
        /// </summary>
        public string ValidPeriod { get; set; } = string.Empty;

        /// <summary>
        /// 照片Base64数据
        /// </summary>
        public string PhotoBase64 { get; set; } = string.Empty;

        /// <summary>
        /// 读取时间
        /// </summary>
        public DateTime ReadTime { get; set; } = DateTime.Now;

        /// <summary>
        /// 是否读取成功
        /// </summary>
        public bool IsSuccess { get; set; } = false;

        /// <summary>
        /// 错误信息
        /// </summary>
        public string ErrorMessage { get; set; } = string.Empty;

        /// <summary>
        /// 身份证物理卡号
        /// </summary>
        public string MacCard { get; set; } = string.Empty;

        /// <summary>
        /// 打印身份证信息
        /// </summary>
        public void Print()
        {
            Console.WriteLine("========== 身份证信息 ==========");
            Console.WriteLine($"姓名: {Name}");
            Console.WriteLine($"性别: {Gender}");
            Console.WriteLine($"民族: {Nation}");
            Console.WriteLine($"出生日期: {BirthDate}");
            Console.WriteLine($"身份证号: {IDNumber}");
            Console.WriteLine($"地址: {Address}");
            Console.WriteLine($"签发机关: {IssueAuthority}");
            Console.WriteLine($"有效期: {ValidPeriod}");
            Console.WriteLine($"读取时间: {ReadTime:yyyy-MM-dd HH:mm:ss}");
            Console.WriteLine("================================");
        }
    }

    #endregion 身份证信息数据模型
}